#encoding: utf-8

def fib(num):
	''' 生成器 '''
	a, b = 0 , 1
	for _ in range(num):
		a, b = b , a + b
		yield a


class Fib(object):
	""" 迭代器 """
	def __init__(self, num):
		super(Fib, self).__init__()
		self.num = num
		self.a, self.b = 0 , 1
		self.idx = 0

	def __iter__(self):
		return self
		

	def __next__(self):
		if self.idx < self.num:
			self.a , self.b = self.b , self.a + self.b
			self.idx +=1
			return self.a
			raise StopIteration()



''' 
	并发编程 
	Python中实现并发编程的三种方案：多线程、多进程和异步I/O。

	面试题：进程和线程的区别和联系？
	进程 - 操作系统分配内存的基本单位 - 一个进程可以包含一个或多个线程
	线程 - 操作系统分配CPU的基本单位
	
	并发编程（concurrent programming）
	1. 提升执行性能 - 让程序中没有因果关系的部分可以并发的执行
	2. 改善用户体验 - 让耗时间的操作不会造成程序的假死

	多线程程序如果没有竞争资源处理起来通常也比较简单
	当多个线程竞争临界资源的时候如果缺乏必要的保护措施就会导致数据错乱
	说明：临界资源就是被多个线程竞争的资源

'''

import time 
import threading
from concurrent.futures import ThreadPoolExecutor
from time import sleep
from random import randint



class Account(object):
	"""docstring for Account"""
	def __init__(self, balance = 0):
		super(Account, self).__init__()
		self.balance = balance
		lock = threading.Lock()
		self.condition =threading.Condition(lock)

	def withdraw(self, money):
		'''取钱'''
		with self.condition:
			while money > self.balance:
				self.condition.wait()
			new_balance = self.balance - money
			sleep(0.001)
			self.balance = new_balance


	def deposit(self, money):
		with self.condition:
			new_balance = self.balance + money
			time.sleep(0.001)
			self.balance = new_balance
			self.condition.notify_all()


# class AddMoneyThread(threading.Thread):
# 	"""docstring for AddMoneyThread"""
# 	def __init__(self, account, money):
# 		super(AddMoneyThread, self).__init__()
# 		self.account = account
# 		self.money = money
		
# 	def run(self):
# 		self.account.deposit(self.money)
		
def add_money(account):
	while True:
		money = randint(10, 30)
		account.deposit(money)
		print(threading.concurrent_thread().name, ':' , money, '<------', account.balance)
		sleep(0.5)
	

def sub_money(account):
	while True:
		money = randint(10, 30)
		account.withdraw(money)
		print(threading.concurrent_thread().name, ':' , money, '<------', account.balance)
		sleep(1)

def main():

	# f = Fib(10)
	# print(f.__next__())
	account = Account(100)
	print('123')
	# pool = ThreadPoolExecutor(max_workers =10)
	# futures = []
	# for _ in range(100):
	# 	future = pool.submit(account.deposit, 1)
	# 	futures.append(future)
	
	# pool.shutdown()

	# for future in futures:
	# 	future.result()
	# print(account.balance)
		
	with ThreadPoolExecutor(max_workers = 10) as pool:
		for _ in range(5):
			pool.submit(add_money, account)
			pool.submit(sub_money, account)




if __name__ == '__main__':
	main()

